package com.hqd.ch03.v11.spel.ast;

import com.hqd.ch03.v11.spel.EvaluationContext;
import com.hqd.ch03.v11.spel.PropertyAccessor;
import com.hqd.ch03.v11.spel.standard.ExpressionState;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ArrayUtils;

import java.util.List;

/**
 * 获取类属性
 */
public class PropertyOrFieldReference extends SpelNodeImpl {
    private final String name;

    public PropertyOrFieldReference(String propertyOrFieldName, int startPos, int endPos) {
        super(startPos, endPos);
        this.name = propertyOrFieldName;
    }

    @Override
    public Object getValue(ExpressionState state) {
        try {
            return readProperty(state.getActiveContextObject(), state.getEvaluationContext(), name);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 读取类属性
     *
     * @param contextObject
     * @param evalContext
     * @param name
     * @return
     */
    private Object readProperty(Object contextObject, EvaluationContext evalContext, String name) {
        try {
            /**
             * 获取对象访问器
             */
            List<PropertyAccessor> propertyAccessors = evalContext.getPropertyAccessors();
            for (PropertyAccessor accessor : propertyAccessors) {
                Class<?>[] specificTargetClasses = accessor.getSpecificTargetClasses();
                /**
                 * 如果遇到可以解析的类型，用对象访问器获取相应对象
                 * 否则，直接获取
                 */
                if (ArrayUtils.contains(specificTargetClasses, contextObject.getClass())) {
                    if (accessor.canRead(evalContext, contextObject, name)) {
                        return accessor.read(evalContext, contextObject, name);
                    }
                }
            }
            return PropertyUtils.getProperty(contextObject, name);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String getName() {
        return name;
    }
}
